package io.gitee.zhangbinhub.acp.core.common.security

/**
 * @since JDK 17
 */

import io.gitee.zhangbinhub.acp.core.common.base.BaseEncrypt
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.Key
import java.security.Security
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec

object SM4Encrypt : BaseEncrypt() {
    init {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(BouncyCastleProvider())
        }
    }

    private val ZERO_IVC = byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

    private const val CRYPT_TYPE = "SM4/ECB/PKCS7Padding"

    /**
     * 加密
     *
     * @param plainText 待加密字符串
     * @param key       密钥
     * @param cryptType 加密类型，默认 SM4/ECB/PKCS7Padding
     * - SM4/ECB/NoPadding
     * - SM4/CBC/NoPadding
     * - SM4/ECB/PKCS5Padding
     * - SM4/CBC/PKCS5Padding
     * - SM4/ECB/PKCS7Padding
     * - SM4/CBC/PKCS7Padding
     * @return 密文
     */
    @JvmStatic
    @Throws(Exception::class)
    @JvmOverloads
    fun encrypt(
        plainText: String, key: Key, cryptType: String = CRYPT_TYPE,
        inputEncode: ByteEncodeEnum = ByteEncodeEnum.BYTE,
        outputEncode: ByteEncodeEnum = ByteEncodeEnum.BASE64,
        iv: ByteArray = ZERO_IVC
    ): String {
        val cipher = Cipher.getInstance(cryptType)
        if (cryptType.uppercase().contains("ECB")) {
            cipher.init(Cipher.ENCRYPT_MODE, key)
        } else {
            cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
        }
        return encodeToString(cipher.doFinal(decodeToBytes(plainText, inputEncode)), outputEncode)
    }

    /**
     * 解密
     *
     * @param encryptedText 加密字符串
     * @param key           密钥
     * @param cryptType     加密类型，默认 AES/ECB/PKCS5Padding
     * - SM4/ECB/NoPadding
     * - SM4/CBC/NoPadding
     * - SM4/ECB/PKCS5Padding
     * - SM4/CBC/PKCS5Padding
     * - SM4/ECB/PKCS7Padding
     * - SM4/CBC/PKCS7Padding
     * @return 明文
     */
    @JvmStatic
    @Throws(Exception::class)
    @JvmOverloads
    fun decrypt(
        encryptedText: String, key: Key, cryptType: String = CRYPT_TYPE,
        inputEncode: ByteEncodeEnum = ByteEncodeEnum.BASE64,
        outputEncode: ByteEncodeEnum = ByteEncodeEnum.BYTE,
        iv: ByteArray = ZERO_IVC
    ): String {
        val cipher = Cipher.getInstance(cryptType)
        if (cryptType.uppercase().contains("ECB")) {
            cipher.init(Cipher.DECRYPT_MODE, key)
        } else {
            cipher.init(Cipher.DECRYPT_MODE, key, IvParameterSpec(iv))
        }
        return encodeToString(cipher.doFinal(decodeToBytes(encryptedText, inputEncode)), outputEncode)
    }

}